package com.gelingqin.es.springbootdemo.entity;

import java.util.ArrayList;
import java.util.List;

import org.elasticsearch.index.query.ExistsQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder.Type;
import org.elasticsearch.index.query.PrefixQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;



/**
 * 查询组装类
 * @author 86133
 *
 */
public class Query {
  public static final int DEFAULT_PAGE = 1;
  public static final int DEFAULT_PAGE_SIZE = 10;
  /**
   * most
   */
  private static final String MOST = "most";
  /**
   * best
   */
  private static final String BEST = "best";
  /**
   * 关键字
   */
  private static final String KEYWORD = ".keyword";
  /**
   * 升序
   */
  private static final String ASC = "asc";


  /** 页码 */
  private int page;
  /** 分页大小 */
  private int size;
  private Integer from;
  private List<QueryBuilder> filters;
  private List<QueryBuilder> musts;
  private List<QueryBuilder> mustNots;
  private List<QueryBuilder> shoulds;
  private List<String> indices;
  /** 设置不返回的字段 */
  private List<String> excludes;
  /** 设置返回的字段 */
  private List<String> includes;
  /**
   * 索引模式
   */
  private String indexPattern;



  public int getPage() {
    return this.page;
  }

  public void setPage(final int page) {
    this.page = page;
  }

  public int getSize() {
    return this.size;
  }

  public void setSize(final int size) {
    this.size = size;
  }



  public List<QueryBuilder> getFilters() {
    return this.filters;
  }

  public List<QueryBuilder> getMusts() {
    return this.musts;
  }

  public List<QueryBuilder> getMustNots() {
    return this.mustNots;
  }

  public List<QueryBuilder> getShoulds() {
    return this.shoulds;
  }

  private Query() {
    this.page = 1;
    this.size = 10;
    this.filters = new ArrayList<QueryBuilder>();
    this.musts = new ArrayList<QueryBuilder>();
    this.mustNots = new ArrayList<QueryBuilder>();
    this.shoulds = new ArrayList<QueryBuilder>();
    this.excludes = new ArrayList<>();
    this.includes = new ArrayList<>();
  }

  public static Query build(String indexPattern) {
    final Query query = new Query();
    query.setIndexPattern(indexPattern);
    return query;
  }

  public static Query build(final int page, final int size,String indexPattern) {
    final Query query = new Query();
    query.setPage(page);
    query.setSize(size);
    query.setIndexPattern(indexPattern);
    return query;
  }


  /**
   * operator默认为or
   *
   * @param name
   * @param text
   * @return
   */
  public Query match(final String name, final String text) {
    if (!this.isEmpty(text)) {
      final MatchQueryBuilder match = QueryBuilders.matchQuery(name, (Object) text);
      this.musts.add((QueryBuilder) match);
    }
    return this;
  }
  /**
   * 不匹配
   * operator默认为or
   * @param name
   * @param text
   * @return
   */
  public Query notMatch(final String name, final String text) {
    if (!this.isEmpty(text)) {
      final MatchQueryBuilder match = QueryBuilders.matchQuery(name, (Object) text);
      this.mustNots.add((QueryBuilder) match);
    }
    return this;
  }

  /**
   * 通配符查询，支持* 任意字符串；？任意一个字符
   *
   * @param name 字段名称
   * @param text 查询内容
   * @return
   */
  public Query wildcardQuery(final String name, final String text) {
    if (!this.isEmpty(text)) {
      final WildcardQueryBuilder matchQueryBuilder = QueryBuilders.wildcardQuery(name, text);
      this.musts.add(matchQueryBuilder);
    }
    return this;
  }

  /**
   * 匹配分词前缀 如果字段没分词，就匹配整个字段前缀 类似 "like%"
   *
   * @param name 字段名称
   * @param text 查询内容
   * @return
   */
  public Query prefixQuery(final String name, final String text) {
    if (!this.isEmpty(text)) {
      final PrefixQueryBuilder matchQueryBuilder = QueryBuilders.prefixQuery(name, text);
      this.musts.add(matchQueryBuilder);

    }
    return this;
  }

  /**
   *
   * @param name
   * @param text
   * @param minimumShouldMatch 最小匹配度
   * @return
   */
  public Query match(final String name, final String text, String minimumShouldMatch) {
    if (!this.isEmpty(text)) {
      final MatchQueryBuilder match =
          QueryBuilders.matchQuery(name, (Object) text).minimumShouldMatch(minimumShouldMatch);
      this.musts.add((QueryBuilder) match);
    }
    return this;
  }


  /**
   *
   * @param text
   * @param type most-匹配越多的得分越高， best-完全匹配的文档评分会比较靠前，未完全匹配的文档评分乘以0.3的系数
   * @return
   */
  public Query multiMatch(final String text, String type, final String... fieldNames) {
    Type qtype = null;
    if (MOST.equals(type)) {
      qtype = Type.MOST_FIELDS;
    } else if (BEST.equals(type)) {
      qtype = Type.BEST_FIELDS;
    } else {
      qtype = Type.BEST_FIELDS;
    }
    if (!this.isEmpty(text)) {
      // 没有完全匹配的会乘以0.3
      MultiMatchQueryBuilder multiMatchQueryBuilder =
          QueryBuilders.multiMatchQuery((Object) text, fieldNames).type(qtype).tieBreaker(0.3f);
      this.musts.add((QueryBuilder) multiMatchQueryBuilder);
    }
    return this;
  }

  public Query matchAll() {
    this.musts.add((QueryBuilder) QueryBuilders.matchAllQuery());
    return this;
  }

  public Query isNotNull(String name) {
    final ExistsQueryBuilder exist = QueryBuilders.existsQuery(name);
    // QueryBuilders.
    if (!name.contains(KEYWORD)) {
      name += ".keyword";
    }
    final TermQueryBuilder space = QueryBuilders.termQuery(name, "");
    this.musts.add((QueryBuilder) exist);
    this.mustNots.add((QueryBuilder) space);
    return this;
  }

  public Query isNull(String name) {
    if (!name.contains(KEYWORD)) {
      name += ".keyword";
    }
    final TermQueryBuilder space = QueryBuilders.termQuery(name, "");
    this.shoulds.add((QueryBuilder) space);
    return this;
  }

  public Query analyse(final String name, final String text) {
    if (!this.isEmpty(text)) {
      final QueryStringQueryBuilder queryString = QueryBuilders.queryStringQuery(name + ":" + text);
      this.shoulds.add((QueryBuilder) queryString);
    }
    return this;
  }

  public Query rangeGte(final String name, final Object value) {
    if (value != null) {
      final RangeQueryBuilder range = QueryBuilders.rangeQuery(name).gte(value);
      this.filters.add((QueryBuilder) range);
    }
    return this;
  }

  public Query rangeLte(final String name, final Object value) {
    if (value != null) {
      final RangeQueryBuilder range = QueryBuilders.rangeQuery(name).lte(value);
      this.filters.add((QueryBuilder) range);
    }
    return this;
  }

  public Query rangeGt(final String name, final Object value) {
    if (value != null) {
      final RangeQueryBuilder range = QueryBuilders.rangeQuery(name).gt(value);
      this.filters.add((QueryBuilder) range);
    }
    return this;
  }

  public Query rangeLt(final String name, final Object value) {
    if (value != null) {
      final RangeQueryBuilder range = QueryBuilders.rangeQuery(name).lt(value);
      this.filters.add((QueryBuilder) range);
    }
    return this;
  }

  /**
   * 添加不返回字段
   *
   * @param exclude
   * @return
   */
  public Query addExclude(String exclude) {
    excludes.add(exclude);
    return this;
  }

  /**
   * 添加返回字段
   *
   * @param include
   * @return
   */
  public Query addInclude(String include) {
    includes.add(include);
    return this;
  }



  private boolean isEmpty(final String text) {
    return text == null || text.trim().length() == 0;
  }

  public List<String> getIndices() {
    return indices;
  }

  public void setIndices(List<String> indices) {
    this.indices = indices;
  }

  public Integer getFrom() {
    if (this.from != null) {
      return from;
    } else {
      return (page - 1) * size;
    }
  }

  public void setFrom(Integer from) {
    this.from = from;
  }

  public List<String> getExcludes() {
    return excludes;
  }

  public void setExcludes(List<String> excludes) {
    this.excludes = excludes;
  }

  public List<String> getIncludes() {
    return includes;
  }

  public void setIncludes(List<String> includes) {
    this.includes = includes;
  }

public String getIndexPattern() {
	return indexPattern;
}

public void setIndexPattern(String indexPattern) {
	this.indexPattern = indexPattern;
}


}
